﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OpenCvSharp;
using OpenCvSharp.Blob;

namespace RecognitionNumbers
{
    public class SearchRectangle : Filter
    {
        protected List<Rectangle> coordinatesRectangle_;
        protected List<IplImage> imageRectangle_;
       

        public SearchRectangle(IplImage iamge)
        {
            coordinatesRectangle_ = new List<Rectangle>();
            imageRectangle_ = new List<IplImage>();
            search(iamge);
        }

        public SearchRectangle(IplImage изображение, int порогБинаризации, int процентЦветных, int процентЧерногоНиз, int процентЧерногоВерх, double соттношениеСторон, double отклонениеСоотношения)
        {
            coordinatesRectangle_ = new List<Rectangle>();
            imageRectangle_ = new List<IplImage>();
            search(изображение, порогБинаризации, процентЦветных, процентЧерногоНиз, процентЧерногоВерх,  соттношениеСторон,  отклонениеСоотношения);
        }

        public List<Rectangle> coordinatesRectangle
        {
            get
            {
                return coordinatesRectangle_;
            }

        }

        public IplImage cvSubImage(IplImage original, CvRect rect)
        {
             IplImage sub = new IplImage(rect.Width,rect.Height,original.Depth, original.NChannels);
                    for (int i=0;i<sub.Width;i++)
                        for (int j = 0; i < sub.Height; j++)
                        {
                            sub[i, j] = original[i, j];
                        }
            return sub;
        }

        public virtual List<IplImage> imageRectangle
        {
            get
            {
                imageRectangle_.Clear();
                foreach (Rectangle k in coordinatesRectangle_)
                {
                    int left, right, top, buttom;
                    double k1, k2, k3, k4;
                    if (k.lt.X < k.lb.X) left = k.lt.X; else left = k.lb.X;
                    if (k.rt.X > k.lb.X) right = k.rt.X; else right = k.rb.X;
                    if (k.lt.Y < k.rt.Y) top = k.lt.Y; else top = k.rt.Y;
                    if (k.lb.Y > k.rb.Y) buttom = k.lb.Y; else buttom = k.rb.Y;
                  
                    IplImage sub = original.GetSubImage(new CvRect(left, top, right - left, buttom - top));
                     
                

                    /*CvPoint[] u = new CvPoint[4];
                    u[0] =new CvPoint(left, top);
                    u[1] = new CvPoint(left, k.lt.Y);
                    u[2] = new CvPoint(right, k.rt.Y);
                    u[3] = new CvPoint(right, top);
                    for */
                    k1 = (Convert.ToDouble(k.rt.Y - k.lt.Y) / Convert.ToDouble(k.rt.X - k.lt.X));
                    k2 = (Convert.ToDouble(k.rb.Y - k.lb.Y) / Convert.ToDouble(k.rb.X - k.lb.X));
                    double t = k.lt.Y - top;
                    double b = k.lb.Y - top;
                    int h = ((k.lb.Y - k.lt.Y) + (k.rb.Y - k.rt.Y)) / 2;
                    /*
                    k3 = Math.Atan(Convert.ToDouble(k.lb.Y - k.lt.Y) / Convert.ToDouble(k.lb.X - k.lt.X));
                    k4 = Math.Atan(Convert.ToDouble(k.rb.Y - k.rt.Y) / Convert.ToDouble(k.rb.X - k.rt.X));
                    */
                    double ks = (k1 + k2) / 2;
                    for (int i = 1; i < sub.Width; i++)
                        for (int j = 1; j < sub.Height; j++)
                        {
                            if (!((j < i * ks + t) | (j > i * ks + b)))
                                sub[j - Convert.ToInt32(Math.Abs( Math.Truncate(i * ks + t))), i] = sub[j, i];
                        }
                    sub = sub.GetSubImage(new CvRect(0, 0, sub.Width, h));

                    //System.Windows.Forms.MessageBox.Show(Convert.ToString(k1) + " " + Convert.ToString(k2) + " " + Convert.ToString(k3) + " " + Convert.ToString(k4));
                    imageRectangle_.Add(sub);
                }
                return imageRectangle_;
            }

        }

        

        public override OpenCvSharp.IplImage input
        {
            get
            {
                return original;
            }
            set
            {
                search(value);
            }
        }

        public override OpenCvSharp.IplImage output
        {
            get
            {
                foreach (Rectangle o in coordinatesRectangle_)
                {
                    transformed.Line(o.lt, o.rt, CvColor.Red, 1);
                    transformed.Line(o.rt, o.rb, CvColor.Red, 1);
                    transformed.Line(o.rb, o.lb, CvColor.Red, 1);
                    transformed.Line(o.lb, o.lt, CvColor.Red, 1);


                }
                return transformed;
            }

        }

        public virtual void search(IplImage image)
        {
            original = image;
            transformed = image.Clone();
            Gray gray = new Gray(original);
            Binarization bw = new Binarization(gray.output, 100);
            IplImage imgLabel = new IplImage(original.Size, BitDepth.F32, 1);
            CvBlobs blobs = new CvBlobs();
            uint result = blobs.Label(bw.output, imgLabel);
            bool t = true;
            foreach (KeyValuePair<uint, CvBlob> item in blobs)
            {
                CvBlob b = item.Value;
                CvContourChainCode cc = b.Contour;
                CvPoint[] polygon = cc.ConvertChainCodesToPolygon().ToArray<CvPoint>();
                CvPoint lt = polygon[0];
                foreach (CvPoint temp in polygon)
                {
                    if (Math.Sqrt(Math.Pow(temp.X - b.MinX, 2) + Math.Pow(temp.Y - b.MinY, 2)) < Math.Sqrt(Math.Pow(lt.X - b.MinX, 2) + Math.Pow(lt.Y - b.MinY, 2)))
                        lt = temp;
                }
                CvPoint rt = polygon[0];
                foreach (CvPoint temp in polygon)
                {
                    if (Math.Sqrt(Math.Pow(temp.X - b.MaxX, 2) + Math.Pow(temp.Y - b.MinY, 2)) < Math.Sqrt(Math.Pow(rt.X - b.MaxX, 2) + Math.Pow(rt.Y - b.MinY, 2)))
                        rt = temp;
                }
                CvPoint rb = polygon[0];
                foreach (CvPoint temp in polygon)
                {
                    if (Math.Sqrt(Math.Pow(temp.X - b.MaxX, 2) + Math.Pow(temp.Y - b.MaxY, 2)) < Math.Sqrt(Math.Pow(rb.X - b.MaxX, 2) + Math.Pow(rb.Y - b.MaxY, 2)))
                        rb = temp;
                }
                CvPoint lb = polygon[0];
                foreach (CvPoint temp in polygon)
                {
                    if (Math.Sqrt(Math.Pow(temp.X - b.MinX, 2) + Math.Pow(temp.Y - b.MaxY, 2)) < Math.Sqrt(Math.Pow(lb.X - b.MinX, 2) + Math.Pow(lb.Y - b.MaxY, 2)))
                        lb = temp;
                }
                double t4 = Math.Sqrt(Math.Pow(lb.X - b.MinX, 2) + Math.Pow(lb.Y - b.MaxY, 2));
                double t3 = Math.Sqrt(Math.Pow(rb.X - b.MaxX, 2) + Math.Pow(rb.Y - b.MaxY, 2));
                double t2 = Math.Sqrt(Math.Pow(rt.X - b.MaxX, 2) + Math.Pow(rt.Y - b.MinY, 2));
                double t1 = Math.Sqrt(Math.Pow(lt.X - b.MinX, 2) + Math.Pow(lt.Y - b.MinY, 2));
                if (((rt.X - lt.X) > 10) & ((rb.X - lb.X) > 10) & ((rb.Y - rt.Y) > 10) & ((lb.Y - lt.Y) > 10) & (t1 < b.Rect.Height * 0.3) & (t2 < b.Rect.Height * 0.3) & (t3 < b.Rect.Height * 0.3) & (t4 < b.Rect.Height * 0.3) & ((t1 < b.Rect.Height * 0.1) | (t2 < b.Rect.Height * 0.1) | (t3 < b.Rect.Height * 0.1) | (t4 < b.Rect.Height * 0.1)) & (Convert.ToDouble(b.Rect.Width) / Convert.ToDouble(b.Rect.Height) > 2.5) & (b.Rect.Width > original.Size.Width * 0.05))
                {
                    coordinatesRectangle_.Add(new Rectangle(lt, rt, rb, lb));
                }
            }
            if (coordinatesRectangle_.Count > 0)
            {
                List<Rectangle> te = new List<Rectangle>();
                foreach (Rectangle o in coordinatesRectangle_)
                {
                    foreach (Rectangle m in coordinatesRectangle_)
                    {
                        if (((m.lt.X > o.lt.X) & (m.lt.Y > o.lt.Y) & (m.lt.X < o.rb.X) & (m.lt.Y < o.rb.Y)) | ((m.rb.X > o.lt.X) & (m.rb.Y > o.lt.Y) & (m.rb.X < o.rb.X) & (m.rb.Y < o.rb.Y)))
                        {
                            te.Add(o);
                            break;
                        }
                    }
                }
                foreach (Rectangle o in te)
                {
                    coordinatesRectangle_.Remove(o);
                }
                te.Clear();
                foreach (Rectangle o in coordinatesRectangle_)
                {

                    int sr;
                    int color = 0;
                    CvSize size = new CvSize(50, 20);

                    IplImage dstLinear = new IplImage(size, image.Depth, image.NChannels);
                    Cv.Resize(image.GetSubImage(new CvRect(o.lt.X, o.lt.Y, (o.rt.X - o.lt.X), (o.rb.Y - o.rt.Y))), dstLinear, Interpolation.Linear);
                    System.Drawing.Bitmap im = dstLinear.ToBitmap();

                    for (int i = 0; i < im.Width; i++)
                        for (int j = 0; j < im.Height; j++)
                        {
                            sr = ((im.GetPixel(i, j).B + im.GetPixel(i, j).G + im.GetPixel(i, j).R) / 3);
                            if ((sr > 50) & (sr < 200))
                                if (
                                    ((im.GetPixel(i, j).B > sr * 1.2) | (im.GetPixel(i, j).B < sr * 0.8)) |
                                    ((im.GetPixel(i, j).G > sr * 1.2) | (im.GetPixel(i, j).G < sr * 0.8)) |
                                    ((im.GetPixel(i, j).R > sr * 1.2) | (im.GetPixel(i, j).R < sr * 0.8))
                                )
                                    color++;
                        }
                    if ((color > ((im.Height) * (im.Width)) * (0.2)) )
                    {
                        te.Add(o);

                    }

                }
                foreach (Rectangle o in te)
                {
                    coordinatesRectangle_.Remove(o);
                }




            }
        }


        public virtual void search(IplImage изображение, int порогБинаризации, int процентЦветных, int процентЧерногоНиз, int процентЧерногоВерх, double соттношениеСторон, double отклонениеСоотношения)
        {
            original = изображение;
            transformed = изображение.Clone();
            Gray сераяКартинка = new Gray(original);
            Binarization чбКартинка = new Binarization(сераяКартинка.output, порогБинаризации);
            IplImage imgLabel = new IplImage(original.Size, BitDepth.F32, 1);
            CvBlobs blobs = new CvBlobs();
            uint result = blobs.Label(чбКартинка.output, imgLabel);
            bool t = true;
            foreach (KeyValuePair<uint, CvBlob> item in blobs)
            {
                CvBlob b = item.Value;
                CvContourChainCode cc = b.Contour;
                CvPoint[] polygon = cc.ConvertChainCodesToPolygon().ToArray<CvPoint>();
                CvPoint lt = polygon[0];
                foreach (CvPoint temp in polygon)
                {
                    if (Math.Sqrt(Math.Pow(temp.X - b.MinX, 2) + Math.Pow(temp.Y - b.MinY, 2)) < Math.Sqrt(Math.Pow(lt.X - b.MinX, 2) + Math.Pow(lt.Y - b.MinY, 2)))
                        lt = temp;
                }
                CvPoint rt = polygon[0];
                foreach (CvPoint temp in polygon)
                {
                    if (Math.Sqrt(Math.Pow(temp.X - b.MaxX, 2) + Math.Pow(temp.Y - b.MinY, 2)) < Math.Sqrt(Math.Pow(rt.X - b.MaxX, 2) + Math.Pow(rt.Y - b.MinY, 2)))
                        rt = temp;
                }
                CvPoint rb = polygon[0];
                foreach (CvPoint temp in polygon)
                {
                    if (Math.Sqrt(Math.Pow(temp.X - b.MaxX, 2) + Math.Pow(temp.Y - b.MaxY, 2)) < Math.Sqrt(Math.Pow(rb.X - b.MaxX, 2) + Math.Pow(rb.Y - b.MaxY, 2)))
                        rb = temp;
                }
                CvPoint lb = polygon[0];
                foreach (CvPoint temp in polygon)
                {
                    if (Math.Sqrt(Math.Pow(temp.X - b.MinX, 2) + Math.Pow(temp.Y - b.MaxY, 2)) < Math.Sqrt(Math.Pow(lb.X - b.MinX, 2) + Math.Pow(lb.Y - b.MaxY, 2)))
                        lb = temp;
                }
                double t4 = Math.Sqrt(Math.Pow(lb.X - b.MinX, 2) + Math.Pow(lb.Y - b.MaxY, 2));
                double t3 = Math.Sqrt(Math.Pow(rb.X - b.MaxX, 2) + Math.Pow(rb.Y - b.MaxY, 2));
                double t2 = Math.Sqrt(Math.Pow(rt.X - b.MaxX, 2) + Math.Pow(rt.Y - b.MinY, 2));
                double t1 = Math.Sqrt(Math.Pow(lt.X - b.MinX, 2) + Math.Pow(lt.Y - b.MinY, 2));
                if (((rt.X - lt.X) > 10) & ((rb.X - lb.X) > 10) & ((rb.Y - rt.Y) > 10) & ((lb.Y - lt.Y) > 10) & (t1 < b.Rect.Height * 0.3) & (t2 < b.Rect.Height * 0.3) & (t3 < b.Rect.Height * 0.3) & (t4 < b.Rect.Height * 0.3) & ((t1 < b.Rect.Height * 0.1) | (t2 < b.Rect.Height * 0.1) | (t3 < b.Rect.Height * 0.1) | (t4 < b.Rect.Height * 0.1)) & (Math.Abs((Convert.ToDouble(b.Rect.Width) / Convert.ToDouble(b.Rect.Height))-соттношениеСторон) <(отклонениеСоотношения/100*соттношениеСторон)  ) & (b.Rect.Width > original.Size.Width * 0.05))
                {
                    coordinatesRectangle_.Add(new Rectangle(lt, rt, rb, lb));
                }
            }
            if (coordinatesRectangle_.Count > 0)
            {
                List<Rectangle> te = new List<Rectangle>();
                foreach (Rectangle o in coordinatesRectangle_)
                {
                    foreach (Rectangle m in coordinatesRectangle_)
                    {
                        if (((m.lt.X > o.lt.X) & (m.lt.Y > o.lt.Y) & (m.lt.X < o.rb.X) & (m.lt.Y < o.rb.Y)) | ((m.rb.X > o.lt.X) & (m.rb.Y > o.lt.Y) & (m.rb.X < o.rb.X) & (m.rb.Y < o.rb.Y)))
                        {
                            te.Add(o);
                            break;
                        }
                    }
                }
                foreach (Rectangle o in te)
                {
                    coordinatesRectangle_.Remove(o);
                }
                te.Clear();
                foreach (Rectangle o in coordinatesRectangle_)
                {

                    int sr;
                    int color = 0;
                    int black = 0;
                    CvSize size = new CvSize(50, 20);

                    IplImage dstLinear = new IplImage(size, изображение.Depth, изображение.NChannels);
                    Cv.Resize(изображение.GetSubImage(new CvRect(o.lt.X, o.lt.Y, (o.rt.X - o.lt.X), (o.rb.Y - o.rt.Y))), dstLinear, Interpolation.Linear);
                    for (int i = 0; i < dstLinear.Width-1; i++)
                        for (int j = 0; j < dstLinear.Height-1; j++)
                        {
                            CvScalar s = dstLinear[j, i];
                            double st = (s.Val0 + s.Val1 + s.Val2)/3;
                            if ((st > 50) & (st < 200))
                            {
                                if (
                                    ((s.Val0 > st * 1.2) | (s.Val0 < st * 0.8)) |
                                    ((s.Val1 > st * 1.2) | (s.Val1 < st * 0.8)) |
                                    ((s.Val2 > st * 1.2) | (s.Val2 < st * 0.8))
                                )
                                    color++;

                            }
                            if (st<порогБинаризации) black++;
                        }
                    /*
                    System.Drawing.Bitmap im = dstLinear.ToBitmap();

                    for (int i = 0; i < im.Width; i++)
                        for (int j = 0; j < im.Height; j++)
                        {
                            sr = ((im.GetPixel(i, j).B + im.GetPixel(i, j).G + im.GetPixel(i, j).R) / 3);
                            if ((sr > 50) & (sr < 200))
                                if (
                                    ((im.GetPixel(i, j).B > sr * 1.2) | (im.GetPixel(i, j).B < sr * 0.8)) |
                                    ((im.GetPixel(i, j).G > sr * 1.2) | (im.GetPixel(i, j).G < sr * 0.8)) |
                                    ((im.GetPixel(i, j).R > sr * 1.2) | (im.GetPixel(i, j).R < sr * 0.8))
                                )
                                    color++;
                        }
                     

                    if ((color < ((im.Height) * (im.Width)) * Convert.ToDouble(процентНиз) / 100) | (color > ((im.Height) * (im.Width)) * Convert.ToDouble(процентВерх) / 100))
                    {
                        te.Add(o);

                    }
                     */
                    if ((color > ((dstLinear.Height) * (dstLinear.Width)) * Convert.ToDouble(процентЦветных) / 100) | (black > ((dstLinear.Height) * (dstLinear.Width)) * Convert.ToDouble(процентЧерногоВерх) / 100)| (black < ((dstLinear.Height) * (dstLinear.Width)) * Convert.ToDouble(процентЧерногоНиз) / 100))
                    {
                        te.Add(o);

                    }

                }
                foreach (Rectangle o in te)
                {
                    coordinatesRectangle_.Remove(o);
                }
            }
        }
    }
}
